// 该类实现时间轮，进行所有任务的管理，触发以及运行
#pragma once
#include "Log.hpp"

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimerTask
{
private:
    uint64_t _id;         // 定时器任务对象id
    uint32_t _timeout;    // 定时任务的超时时间
    bool _canceled;       // false-表示没有被取消，true-表示被取消
    TaskFunc _task_cb;    // 定时器要执行的定时任务
    ReleaseFunc _release; // 用于删除TimerWheel中保存的定时器对象信息

public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &cb)
        : _id(id), _timeout(delay), _task_cb(cb), _canceled(false) {}

    ~TimerTask()
    {
        if (_canceled == false)
            _task_cb(); // 如果任务未被取消，执行任务回调。
        if (_release)
            _release(); // 调用释放回调，清理任务信息。
    }

    void Cancel() { _canceled = true; }
    void SetRelease(const ReleaseFunc &cb) { _release = cb; }
    uint32_t DelayTime() { return _timeout; } // 返回任务超时时间
};

class EventLoop;
class Channel;
class TimerWheel
{
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;

private:
    int _tick;     // 当前时间轮的的秒针，走到哪里，哪里就释放执行
    int _capacity; // 时间轮的容量 -- 最大延迟时间
    std::vector<std::vector<PtrTask>> _wheel;
    // 用weak_ptr来构造出新的shared_ptr用来计数，不过后续要记得释放
    std::unordered_map<uint64_t, WeakTask> _timers; // 快速查找定时任务的哈希表，任务ID作为key，与任务建立联系

    EventLoop *_loop;                        // 事件循环，用于管理定时器的事件。
    int _timerfd;                            // 定时器描述符 -- 可读事件回调就是读取计数器，执行定时任务
    std::unique_ptr<Channel> _timer_channel; // 定时器的Channel对象，用于监听定时器事件。

private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

    static int CreateTimerfd()
    {
        // int timerfd_create(int clockid, int flags);
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0)
        {
            LOG_ERROR("TIMERFD CREATE FAILED!");
            abort();
        }
        // int timerfd_settime(int fd, int flags, struct itimerspec *new, struct itimerspec);
        // 设置定时器为每秒触发一次
        struct itimerspec itime;
        itime.it_value.tv_sec = 1;     // 设置 秒钟
        itime.it_value.tv_nsec = 0;    // 设置 纳秒 第一次超时时间为1s后
        itime.it_interval.tv_sec = 1;  // 同上
        itime.it_interval.tv_nsec = 0; // 第一次超时后，每隔超时的间隔时
        if (timerfd_settime(timerfd, 0, &itime, NULL) < 0)
        {
            LOG_ERROR("TIMERFD SETTIME FAILED!");
            abort();
        }
        return timerfd;
    }

    int ReadTimefd()
    {
        uint64_t times;
        // read读取到的数据times就是从上⼀次read之后超时的次数
        int ret = read(_timerfd, &times, 8);
        if (ret < 0)
        {
            perror("READ TIMERFD FAILED!");
            abort();
        }
        return times;
    }

    // 每秒钟执行一次，清空当前时间轮位置的任务，触发任务的析构函数
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空指定位置的数组，就会把数组中保存的所有管理定时器对象的shared_ptr释放掉.从而执行析构函数
    }

    // 定时器触发时的回调函数，读取定时器事件并执行任务。
    void OnTime()
    {
        int times = ReadTimefd();
        for (int i = 0; i < times; i++)
        {
            RunTimerTask();
        }
    }

    // 添加定时任务到时间轮中，并记录到_timers哈希表
    void TimerAddInLoop(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        if (delay >= _capacity)
        {
            LOG_ERROR("DELAY EXCEEDS TIMERWHEEL CAPACITY!");
            return;
        }
        PtrTask pt(new TimerTask(id, delay, cb));                      // 实例化定时任务对象
        pt->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id)); // 第0个位置是隐藏的this指针。再把任务id绑定进去
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
    }

    // 刷新/延迟定时任务
    void TimerRefreshInLoop(uint64_t id)
    {
        // 通过保存的定时器对象的weak_ptr构造一个shared_ptr出来, 添加到轮子中
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return; // 没找到定时任务, 没法刷新，没法延迟
        }
        PtrTask pt = it->second.lock(); // lock获取weak_ptr管理的对象对应的shared_ptr
        int delay = pt->DelayTime();    // 获取到了初始的延迟时间
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }

    // 取消指定任务ID的定时任务
    void TimerCancelInLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return; // 没找到定时任务, 没法刷新，没法延迟
        }
        PtrTask pt = it->second.lock(); // 当还没有过期才进行取消
        if (pt)
            pt->Cancel();
        else
            LOG_DEBUG("TIMER TASK ALREADY EXPIRED, CANNOT CANCEL!");
    }

public:
    TimerWheel(EventLoop *loop) : _capacity(60), _tick(0), _wheel(_capacity), _loop(loop),
                                  _timerfd(CreateTimerfd()), _timer_channel(new Channel(_loop, _timerfd))
    {
        _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime, this));
        _timer_channel->EnableRead(); // 启动读事件监控
    }

    /*定时器中有个_timers成员，定时器信息的操作有可能在多线程中进行，因此需要考虑线程安全问题*/
    /*如果不想加锁，那就把对定期的所有操作，都放在一个线程中进行*/
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb);

    // 刷新/延迟定时任务
    void TimerRefresh(uint64_t id);
    void TimerCancel(uint64_t id);

    /*这个接口存在线程安全问题--这个接口实际上不能被外界使用者调用,只能在模块内,对应的EventLoop线程内执行*/
    bool HasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return false; // 没找到定时任务, 没法刷新，没法延迟
        }
        return true;
    }
};